#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include "PokerHands.h"
#include "HandStrenth.h"

using namespace std;

extern "C"  
{  
    #include "lua.h"  
    #include "lauxlib.h"  
    #include "lualib.h"  
}  

#if defined(_WIN32) || defined(_WIN64)
#define _DLLExport _declspec(dllexport)
#else
#define _DLLExport 
#endif

static int lua_delete_utils(lua_State* L)
{
    CPokerHands** p = (CPokerHands**)luaL_checkudata(L, 1, "texas_utils");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");
    if (p)
    {
        delete *p;
    }
    return 1;
}

static int lua_get_hands_type(lua_State *L)
{
    int index = 0;
    CardType handcard[2] = {0};
    CardType board_cards[5] = {0};

    for (int i = 0; i < 2; i++)
    {
        index++;
        if (lua_isinteger(L, index))
            handcard[i] = (short)luaL_checkinteger(L, index);
    }
    for (int i = 0; i < 5; i++)
    {
        index++;
        if (lua_isinteger(L, index))
            board_cards[i] = (short)luaL_checkinteger(L, index);
    }

    CPokerHands calculater;
    calculater.SetHands(handcard[0], handcard[1], board_cards);

    unsigned short best_cards[5];
    calculater.CheckHandsType(best_cards);

    int type = calculater.GetHandsType();
    lua_pushinteger(L, type);
    return 1;
}

// 获得牌力
static int lua_get_handstrength(lua_State *L)
{
    int index = 0;
    CardType handcard[2] = {0};
    CardType board_cards[5] = {0};

    for (int i = 0; i < 2; i++)
    {
        index++;
        if (lua_isinteger(L, index))
            handcard[i] = (short)luaL_checkinteger(L, index);
    }

    for (int i = 0; i < 5; i++)
    {
        index++;
        if (lua_isinteger(L, index))
            board_cards[i] = (short)luaL_checkinteger(L, index);
    }

    int stage = 0;
    index++;
    if (lua_isinteger(L, index))
        stage = (short)luaL_checkinteger(L, index);

    int loop = 1000;
    index++;
    if (lua_isinteger(L, index))
        loop = luaL_checkinteger(L, index);

    int num = BOARD_NUM[stage];
    if (num > 5 || num < 0)
    {
        lua_pushnumber(L, 0);
        lua_pushinteger(L, 0);
        lua_pushinteger(L, 0);
        return 3;
    }

    int win = 0;

    float handstrength = 0;
    CardType _board[5];
    Poker poker;
    CardType hands_copy[2] = {handcard[0], handcard[1]};
    poker.deal_cards(hands_copy, 2);
    poker.deal_cards(board_cards, num);
    for (int i = 0; i < num; ++i)
        _board[i] = board_cards[i];
    for (int i = 0; i < loop; ++i)
    {
        Poker rand_poker(poker);
        const CardType *rand_card = rand_poker.rand_cards(5 - num);
        for (int i = 0; i < 5 - num; ++i)
            _board[num + i] = rand_card[i];
        const CardType *opp_card = rand_poker.rand_cards(2);
        if (cmp_hands(handcard, opp_card, _board) > 0)
            ++win;

        // printf("-------------%3d win: %3d----------------\n", i, win);
        // printf("%3d user 0x%X 0x%X |othercard 0x%X 0x%X\n", i, handcard[0], handcard[1], opp_card[0], opp_card[1]);
        // printf("%3d board 0x%X 0x%X 0x%X 0x%X 0x%X\n", i, _board[0], _board[1], _board[2], _board[3], _board[4]);
    }

    handstrength = (1.0 * win) / loop;
    lua_pushnumber(L, handstrength);
    lua_pushinteger(L, win);
    lua_pushinteger(L, loop);
    return 3;
}


// 比较两副牌
static int lua_compare_best_hand(lua_State *L)
{
    int index = 0;
    int handtype1 = 0;
    CardType handcard1[5] = {0};

    index++;
    if (lua_isinteger(L, index))
        handtype1 = (short)luaL_checkinteger(L, index);

    for (int i = 0; i < 5; i++)
    {
        index++;
        if (lua_isinteger(L, index))
            handcard1[i] = (short)luaL_checkinteger(L, index);
    }

    int handtype2 = 0;
    CardType handcard2[5] = {0};

    index++;
    if (lua_isinteger(L, 1))
        handtype2 = (short)luaL_checkinteger(L, 1);

    for (int i = 0; i < 5; i++)
    {
        index++;
        if (lua_isinteger(L, index))
            handcard2[i] = (short)luaL_checkinteger(L, index);
    }

    int ret = CompHandsType(handtype1, handcard1, handtype2, handcard2);
    lua_pushinteger(L, ret);
    return 1;
}

static const luaL_Reg registerInfo[] = {
    {"__gc", lua_delete_utils},
    {"get_handstrength", lua_get_handstrength},
    {"get_hands_type", lua_get_hands_type},
    {"compare_best_hand", lua_compare_best_hand},
    {NULL, NULL}
};


extern "C" _DLLExport int luaopen_lua_texas_utils(lua_State *L)
{
    luaL_newmetatable(L, "texas_utils");
    lua_pushvalue(L, -1);
    lua_setfield(L, -2, "__index");
	luaL_setfuncs(L, registerInfo, 0);

    return 1;
}
